package com.wasu.sdk_ott.provider

import android.content.ContentProvider
import android.content.ContentUris
import android.content.ContentValues
import android.database.Cursor
import android.database.MatrixCursor
import android.database.sqlite.SQLiteQueryBuilder
import android.net.Uri
import android.util.Log
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.wasu.constant.TAG
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_CHANNEL_KYE
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_PROGRAM_ALLDAY_KYE
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_PROGRAM_KYE
import com.wasu.sdk_ott.http.live.IpLiveLoader
import com.wasu.sdk_ott.http.live.addQiuSuoLiveChannelForDvb
import com.wasu.sdk_ott.http.live.getIpLiveDomain
import com.wasu.sdk_ott.http.live.getIpepgDomain
import com.wasu.sdk_ott.http.live.isIpepgDomain
import com.wasu.sdk_ott.http.live.verifyAuthorizeChannel
import com.wasu.sdk_ott.receiver.LiveChannelAuthHelper
import com.wasu.sdk_ott.service.LiveReservationHelper
import java.util.Arrays

/**
 * <p>------------------------------------------------------
 * <p>Copyright (C) 2020 wasu company, All rights reserved.
 * <p>------------------------------------------------------
 * <p> 用于外部接口请求调用
 * <p> uri="com.wasu.module.sdk"
 *
 * @author Created by zhangmz
 * @date on 2023/8/25
 */
open class WasuSdkModuleProvider: ContentProvider() {

    private val uriMatcher = buildUriMatcher()

    /**
     * 关于数据库的操作
     */
    private var dbHelper: DatabaseHelper? = null

    override fun onCreate(): Boolean {
        Log.v(TAG, "------------>> WasuSdkModuleProvider onCreate <<------------")
        return context?.let {
            dbHelper = DatabaseHelper(it)
            true
        }?: false
    }

    override fun getType(uri: Uri): String? {
        return null
    }

    /**
     * @param projection 要放入光标的列的列表。如果为null，则包括所有列
     * @param selection 筛选行时应用的选择条件。如果为null，则包括所有行
     * @param selectionArgs 你可以包括？s，将被selectionArgs中的值替换，以便它们出现在选择中。这些值将被绑定为字符串。
     * @param sortOrder 应该如何对光标中的行进行排序。如果为null，则提供程序可以自由定义排序顺序。
     */
    override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?
    ): Cursor? {
        val match = uriMatcher.match(uri)
        if (match != CODE_WASU_SDK_LIVE_VERSION && match != CODE_WASU_SDK_COLLECT_CHANNEL){
            Log.v(TAG, "wasu_sdk module provider query uri:$uri; match:$match; projection:${Arrays.toString(projection)}; selection:$selection; selectionArgs:${Arrays.toString(selectionArgs)}; sortOrder:$sortOrder")
        }
        return when(match){
            CODE_WASU_SDK_IPLIVE_CHANNEL_GROUP -> {
                if (projection == null || projection.size < 4){
                    Log.e(TAG, "query channel group the projection length must be greater than 4")
                    return null
                }
                val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_IPLIVE))
                val loader = IpLiveLoader(category = projection[3])
                Log.v(TAG, "------------>> module provider start query channel group, cacheKey:$IPLIVE_CACHE_CHANNEL_KYE")
                loader.queryChannelGroupSync(
                    projection[1],
                    projection[2],
                    projection[3],
                    projection[0],
                    IPLIVE_CACHE_CHANNEL_KYE,
                    success = {
                        Log.v(TAG, "query live channel group success")
                        resultCursor.addRow(arrayOf(addQiuSuoLiveChannelForDvb(projection[3], it)))
                    },
                    failure = {
                        Log.v(TAG, "query live channel group failure")
                    }
                )
                Log.v(TAG, "<<------------ module provider end query channel group")
                resultCursor
            }
            CODE_WASU_SDK_IPLIVE_CHANNEL_TIMESHIFT -> {
                if (projection == null || projection.isEmpty()){
                    Log.e(TAG, "query channel time shift the projection length must be greater than 1")
                    return null
                }
                val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_IPLIVE))
                val loader = IpLiveLoader(baseUrl = getIpLiveDomain())
                Log.v(TAG, "------------>> module provider start query channel time shift")
                loader.queryChannelTimeShiftSync(projection[0],
                    success = {
                        resultCursor.addRow(arrayOf(it))
                    },
                    failure = {
                        Log.v(TAG, "query live channel info failure:$it")
                    }
                )
                Log.v(TAG, "<<------------ module provider end query channel time shift")
                resultCursor
            }
            CODE_WASU_SDK_IPLIVE_CHANNEL -> {
                if (projection == null || projection.size < 3){
                    Log.e(TAG, "query live channel the projection length must be greater than 3")
                    return null
                }
                val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_IPLIVE))
                val loader = IpLiveLoader(category = projection[0])
                Log.v(TAG, "------------>> module provider start query channel info")
                loader.queryChannelSync(
                    projection[1], projection[2], projection[0],
                    success = {
                        Log.v(TAG, "query live channel info success")
                        resultCursor.addRow(arrayOf(it))
                    },
                    failure = {
                        Log.v(TAG, "query live channel info failure:$it")
                    }
                )
                Log.v(TAG, "<<------------ module provider end query channel info")
                resultCursor
            }
            CODE_WASU_SDK_IPLIVE_CHANNEL_PURCHASED -> {
                if (projection == null || projection.size < 3){
                    Log.e(TAG, "query live channel purchased the projection length must be greater than 3")
                    return null
                }
                val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_IPLIVE))
                val capIds = projection[1]
                // 标识是讯飞（huifang）回放鉴权，还是4K（zhibo）直播鉴权
                val purType = projection[2]
                Log.v(TAG, "------------>> module provider start query channel auth, capIds:$capIds; size:${projection.size}")
                val result = arrayOf(LiveChannelAuthHelper.loadAuthChannel(projection[0], capIds, purType))
                Log.v(TAG, "<<------------ module provider end query channel auth, result:${result.contentToString()}")
                resultCursor.addRow(result)
                resultCursor
            }
            CODE_WASU_SDK_IPLIVE_PROGRAM -> {
                if (projection == null || projection.size < 10){
                    Log.e(TAG, "query program the projection length must be greater than 10")
                    return null
                }
                val route = if (projection.size > 10) projection[10] else ""
                val category = projection[1]
                val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_IPLIVE))
                val userIpepg = isIpepgDomain(category) && "smartRecommend" != route
                // route == smartRecommend 标识智能推荐屏查询节目单，无论模式，要用IP直播管理系统
                val loader = IpLiveLoader(baseUrl = if (userIpepg) getIpepgDomain() else getIpLiveDomain())
                val channelId = projection[6]
                // type=1 标识所有频道当天节目单，单独key缓存，
                // type=2 对于单个频道所有天数节目单，单独key缓存
                // type=其他，不做缓存，此时cacheKey不使用
                val cacheKey = if ("1" == projection[2]){
                    IPLIVE_CACHE_PROGRAM_ALLDAY_KYE
                }else {
                    "${IPLIVE_CACHE_PROGRAM_KYE}_$channelId"
                }
                Log.v(TAG, "------------>> module provider start query program list, cacheKey:$cacheKey; route:$route")
                loader.queryProgramListSync(
                    projection[2], projection[3], projection[4], projection[5], projection[6], projection[7], projection[8], projection[9],
                    category = projection[1],
                    strategy = projection[0],
                    cacheKey,
                    userIpepg,
                    success = {
                        Log.v(TAG, "query live program list success")
                        resultCursor.addRow(arrayOf(it))
                    },
                    failure = {
                        Log.v(TAG, "query live program list failure:$it")
                    }
                )
                Log.v(TAG, "<<------------ module provider end query program list")
                resultCursor
            }
            // 频道收藏
            CODE_WASU_SDK_COLLECT_CHANNEL -> {
                if (projection == null || projection.isEmpty()){
                    Log.e(TAG, "query live channel collect the projection length must be greater than 1")
                    return null
                }
                val db = dbHelper?.readableDatabase?: return null
                val sqlBuilder = SQLiteQueryBuilder()
                sqlBuilder.tables = FAVORITES_DB_TABLE
                val channelId = selectionArgs?.get(0)
                if (channelId.isNullOrEmpty()){
                    val cursor = sqlBuilder.query(
                        db,
                        arrayOf(FAVORITES_DB_CHID, FAVORITES_DB_ISFAVORITE),
                        "${FAVORITES_DB_ISFAVORITE}=?",
                        arrayOf("1"), null, null,
                        sortOrder?: if ("0" == projection[0]) FAVORITES_SORT_DESC else FAVORITES_SORT_ASC
                    )
                    cursor?.setNotificationUri(context?.contentResolver, uri)
                    val resultCursor = MatrixCursor(arrayOf(RESULT_WASU_SDK_COLLECT))
                    val collectJsonObject = JSONObject()
                    if (cursor?.moveToFirst() == true) {
                        val collectJsonArray = JSONArray()
                        do {
                            val index = cursor.getColumnIndex(FAVORITES_DB_CHID)
                            if (index >= 0){
                                val chId = cursor.getString(index)
                                verifyAuthorizeChannel(chId){
                                    collectJsonArray.add(it)
                                }
                            }
                        }while (cursor.moveToNext())
                        collectJsonObject["chList"] = collectJsonArray
                        val resultJson = collectJsonObject.toJSONString()
                        resultCursor.addRow(arrayOf(resultJson))
                    }
                    cursor?.close()
                    resultCursor
                }else {
                    val cursor = sqlBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder?: if ("0" == projection[0]) FAVORITES_SORT_DESC else FAVORITES_SORT_ASC)
                    cursor?.setNotificationUri(context?.contentResolver, uri)
                    cursor
                }
            }
            // 节目单预约
            CODE_WASU_SDK_RESERVATION_PROGRAM -> {
                val db = dbHelper?.readableDatabase?: return null
                val sqlBuilder = SQLiteQueryBuilder()
                sqlBuilder.tables = RESERVATION_DB_TABLE
                val cursor = sqlBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder?: RESERVATION_SORT)
                cursor?.setNotificationUri(context?.contentResolver, uri)
                cursor
            }
            CODE_WASU_SDK_LIVE_VERSION -> {
                val db = dbHelper?.readableDatabase?: return null
                val sqlBuilder = SQLiteQueryBuilder()
                sqlBuilder.tables = VERSION_DB_TABLE
                val cursor = sqlBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder)
                cursor?.setNotificationUri(context?.contentResolver, uri)
                cursor
            }
            else -> {
                Log.e(TAG, "wasu_sdk module provider query, Unknown uri:$uri")
                null
            }
        }
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        val db = dbHelper?.writableDatabase?: return null
        val match = uriMatcher.match(uri)
        Log.v(TAG, "wasu_sdk module provider insert uri:$uri; match:$match; values:${values?.toString()}")
        var resultUri: Uri? = null
        return when(match){
            // 频道收藏
            CODE_WASU_SDK_COLLECT_CHANNEL -> {
                val id = db.insertOrThrow(FAVORITES_DB_TABLE, null, values)
                if (id == -1L){
                    Log.e(TAG, "channel collect insert id:$id, error")
                }
                resultUri = ContentUris.withAppendedId(FAVORITES_CONTENT_URI, id)
                context?.contentResolver?.notifyChange(resultUri, null)
                if (id == -1L) null else resultUri
            }
            // 节目单预约
            CODE_WASU_SDK_RESERVATION_PROGRAM -> {
                var isValidStartTime = true
                values?.getAsLong(RESERVATION_DB_STARTDATE)?.let {
                    if (it - System.currentTimeMillis() - RESERVATION_CONDITION < 0){
                        Log.e(TAG, "app pass a time which < (current system time + $RESERVATION_CONDITION), so invalid parameter")
                        isValidStartTime = false
                    }
                }
                val isAddLast: Boolean? = values?.getAsBoolean("addlast")
                if (isAddLast != null){
                    values.remove("addlast")
                }
                Log.v(TAG, "------------------->> insert values:${values?.toString()}; isAddLast:$isAddLast")
                if (isValidStartTime){
                    val i = db.insertOrThrow(RESERVATION_DB_TABLE, null, values)
                    resultUri = ContentUris.withAppendedId(RESERVATION_CONTENT_URI, i)
                    context?.contentResolver?.notifyChange(resultUri, null)
                    // 添加新的预约节目单后，重新查询一次数据库，再取最近一次即将到期节目单，停止之前的计时器，重启新计时器
                    if (isAddLast == null || isAddLast){
                        LiveReservationHelper.queryEpReservation(context, db)
                    }
                    resultUri
                } else null
            }
            CODE_WASU_SDK_LIVE_VERSION -> {
                val id = db.insertOrThrow(VERSION_DB_TABLE, null, values)
                if (id == -1L){
                    Log.e(TAG, "channel collect insert id:$id, error")
                }
                resultUri = ContentUris.withAppendedId(LIVE_VERSION_CONTENT_URI, id)
                context?.contentResolver?.notifyChange(resultUri, null)
                resultUri
            }
            else -> {
                Log.e(TAG, "wasu_sdk module provider insert, Unknown uri:$uri")
                null
            }
        }
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
        val db = dbHelper?.writableDatabase?: return 0
        val match = uriMatcher.match(uri)
        Log.v(TAG, "wasu_sdk module provider delete uri:$uri; match:$match; selection:$selection; selectionArgs:${Arrays.toString(selectionArgs)}")
        val id = when(match){
            // 频道收藏
            CODE_WASU_SDK_COLLECT_CHANNEL -> {
                db.delete(FAVORITES_DB_TABLE, selection, selectionArgs)
            }
            // 节目单预约
            CODE_WASU_SDK_RESERVATION_PROGRAM -> {
                db.delete(RESERVATION_DB_TABLE, selection, selectionArgs)
            }
            else -> Log.e(TAG, "wasu_sdk module provider delete, Unknown uri:$uri")
        }
        return id
    }

    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<out String>?
    ): Int {
        val db = dbHelper?.writableDatabase?: return 0
        val match = uriMatcher.match(uri)
        Log.v(TAG, "wasu_sdk module provider update uri:$uri; match:$match; values:${values.toString()}; selection:$selection; selectionArgs:${Arrays.toString(selectionArgs)}")
        val id = when(match){
            // 频道收藏
            CODE_WASU_SDK_COLLECT_CHANNEL -> {
                var count = 0
                var cursor: Cursor? = null
                try {
                    db.beginTransaction()
                    cursor = db.query(FAVORITES_DB_TABLE, arrayOf(RESERVATION_DB_CHID), "$RESERVATION_DB_CHID = ?", arrayOf(values?.getAsString(RESERVATION_DB_CHID)), null, null, null)
                    if ((cursor?.count?: -1) > 0){
                        count = db.update(FAVORITES_DB_TABLE, values, selection, selectionArgs)
                    }else {
                        db.insert(FAVORITES_DB_TABLE, null, values)
                    }
                    db.setTransactionSuccessful()
                }catch (e: Exception){ e.printStackTrace() }
                finally {
                    cursor?.close()
                    db.endTransaction()
                }
                count
            }
            // 节目单预约
            CODE_WASU_SDK_RESERVATION_PROGRAM -> {
                db.update(RESERVATION_DB_TABLE, values, selection, selectionArgs)
            }
            CODE_WASU_SDK_LIVE_VERSION -> {
                db.update(VERSION_DB_TABLE, values, selection, selectionArgs)
            }
            else -> Log.e(TAG, "wasu_sdk module provider update, Unknown uri:$uri")
        }
        context?.contentResolver?.notifyChange(uri, null)
        return id
    }
}